#include <Windows.h>
#include <tchar.h>
#include "resource.h"
#include <commctrl.h>
#include <Windowsx.h>
#pragma comment(lib, "comctl32.lib")

struct SQQZoneTree {
	TCHAR	szName[MAX_PATH];
	int		nParentID;
	int		nID;
};

void AddItemToTree(HWND hTree, HTREEITEM hParent, DWORD nParentID, SQQZoneTree* pQQZoneTree, DWORD dwItemCount)
{
	HTREEITEM hTreeItem;
	for (int ii = 0; ii < dwItemCount; ii++)
	{
		if (pQQZoneTree[ii].nParentID == nParentID)
		{		
			TVITEM tvItem		= {0};
			tvItem.mask			= TVIF_TEXT;
			tvItem.pszText		= pQQZoneTree[ii].szName;
			tvItem.cchTextMax	= MAX_PATH;

			TVINSERTSTRUCT tvis;
			tvis.hInsertAfter	= TVI_LAST;
			tvis.hParent		= hParent;
			tvis.item			= tvItem;
			hTreeItem = TreeView_InsertItem(hTree, &tvis);

			AddItemToTree(hTree, hTreeItem, pQQZoneTree[ii].nID, pQQZoneTree, dwItemCount);
		}
	}

	return;
}

void UpdateTree(HWND hTree, SQQZoneTree* pQQZoneTree, DWORD dwItemCount)
{
	TreeView_DeleteAllItems(hTree);

	HTREEITEM hRootItem = NULL;
	if (NULL != pQQZoneTree && 0 == pQQZoneTree[0].nID)
	{
		TVITEM tvItem		= {0};
		tvItem.mask			= TVIF_TEXT;
		tvItem.pszText		= pQQZoneTree[0].szName;
		tvItem.lParam		= pQQZoneTree[0].nID;
		tvItem.cchTextMax	= MAX_PATH;

		TVINSERTSTRUCT tvis;
		tvis.hInsertAfter	= TVI_ROOT;
		tvis.hParent		= NULL;
		tvis.item			= tvItem;
		hRootItem = TreeView_InsertItem(hTree, &tvis);
	}

	AddItemToTree(hTree, hRootItem, 0, pQQZoneTree, dwItemCount);

	TreeView_Expand(hTree, hRootItem, TVM_EXPAND);
	return;
}

	
DWORD CALLBACK ThreadProc(LPVOID lpData)
{
	HANDLE hEvents[] = {
		CreateEvent(NULL, TRUE, FALSE, _T("F12E7B3C-3710-49e3-B7B8-C116FDDC74FF")),
		CreateEvent(NULL, TRUE, FALSE, _T("BFFB633C-10BB-4e6e-83C9-70ADDAC2748F")),
		CreateEvent(NULL, TRUE, FALSE, _T("63D1722D-4055-4d07-8279-BE7F4930E44F"))
	};

	HWND hDlg = (HWND)lpData;

	bool bQuit = false;
	while (!bQuit)
	{
		DWORD dwID = WaitForMultipleObjects(_countof(hEvents), hEvents, FALSE, INFINITE);
		switch (dwID)
		{
			case 0:
			{
				ResetEvent(hEvents[0]);
				bQuit = true;
				break;
			}
			case 1:
			{
				HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, _T("Global\\QQZone"));
				if (NULL != hFileMapping)
				{
					UCHAR* pMapView = (UCHAR*)MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
					if (NULL != pMapView)
					{
						DWORD dwItemCount = *(DWORD*)pMapView;
		
						SQQZoneTree* pQQZoneTree = (SQQZoneTree*)(pMapView + sizeof(dwItemCount));
											
						HWND hTree = GetDlgItem(hDlg, IDC_TREE);
						UpdateTree(hTree, pQQZoneTree, dwItemCount);
						
						UnmapViewOfFile(pQQZoneTree);
					}
					CloseHandle(hFileMapping);
					
					if (NULL != hEvents[2])
					{
						SetEvent(hEvents[2]);
					}							
				}
				break;
			}
		}
	}

	for (int ii = 0; ii < _countof(hEvents); ii++)
	{
		CloseHandle(hEvents[ii]);
	}

	return 0;
}

int CALLBACK DlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	static HMODULE hModule	= NULL;
	static HANDLE hThread	= NULL;
	switch (nMsg)
	{
		case WM_INITDIALOG:
		{
			InitCommonControls();
			SetWindowText(hDlg, _T("Demo0123"));

			UINT nWidth		= GetSystemMetrics(SM_CXSCREEN);
			UINT nHeight	= GetSystemMetrics(SM_CYSCREEN);
			RECT rtClient;
			GetClientRect(hDlg, &rtClient);
			SetWindowPos(hDlg, NULL, (nWidth - (rtClient.right - rtClient.left)) / 2, (nHeight - (rtClient.bottom - rtClient.top)) / 2, 0, 0, SWP_NOSIZE);
			
			hModule = LoadLibrary(_T("TroyDll.dll"));
			break;
		}
		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
				case IDC_BTNLOAD:
				{
					typedef BOOL (*LOADHOOK)(DWORD, HWND);
					if (NULL != hModule)
					{
						LOADHOOK fnLoadHook = (LOADHOOK)GetProcAddress(hModule, "LoadHook");
						if (NULL != fnLoadHook) 
						{
							HWND hDestApp = FindWindow(_T("QQBattle_MainFrame"), NULL);
							DWORD dwThreadId = GetWindowThreadProcessId(hDestApp, NULL);
							if (0 != dwThreadId)
							{
								fnLoadHook(dwThreadId, hDestApp);

								hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)hDlg, 0, 0);
							}
						}
					}
					break;
				}
				case IDC_BTNUNLOAD:
				{
					typedef BOOL (*UNLOADHOOK)();
					if (NULL != hModule)
					{
						UNLOADHOOK fnUnloadHook = (UNLOADHOOK)GetProcAddress(hModule, "UnloadHook");
						if (NULL != fnUnloadHook) 
						{
							fnUnloadHook();
						}
					}
					break;
				}
			}
			break;
		}
		case WM_CLOSE:
		{
			HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("F12E7B3C-3710-49e3-B7B8-C116FDDC74FF"));
			if (NULL != hEvent)
			{
				SetEvent(hEvent);
				WaitForSingleObject(hThread, INFINITE);
				CloseHandle(hEvent);
			}
			CloseHandle(hThread);

			SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_BTNUNLOAD, BM_CLICK), 0);
			if (NULL != hModule)
			{
				FreeLibrary(hModule);
				hModule = NULL;
			}
			
			PostQuitMessage(0);
			break;
		}
	}

	return 0;
}

BOOL WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR szCmdLine, int nShowCmd)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);

	return TRUE;
}